package xyz.liut.ee.api

import jakarta.servlet.annotation.MultipartConfig
import jakarta.servlet.annotation.WebServlet
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import xyz.liut.ee.bean.FileBean
import xyz.liut.ee.req.printReq
import xyz.liut.ee.req.realPath2Url
import xyz.liut.ee.resp.ResponseEntity
import xyz.liut.ee.resp.sendBy
import xyz.liut.ee.web.BaseServlet
import xyz.liut.ee.web.CONFIG_FILE_PATH
import xyz.liut.ee.web.FAILED_CODE
import xyz.liut.ee.web.SUCCESSFUL_CODE
import xyz.liut.logcat.L
import java.io.File
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardCopyOption

@WebServlet("/upload")
@MultipartConfig
class Upload : BaseServlet() {

    private lateinit var fileDir: File

    override fun doPost(req: HttpServletRequest, resp: HttpServletResponse) {
        req.printReq()

        // 检查保存文件文件夹
        fileDir = File(CONFIG_FILE_PATH)
        if (!fileDir.exists()) {
            if (!fileDir.mkdirs()) {
                val entity: ResponseEntity<Any> = ResponseEntity()
                entity.msg = "上传错误： 创建文件夹失败"
                entity.sendBy(resp)
                return
            }
        }

        // multipart
        if (req.contentType?.contains("multipart") == true) {
            doMultipart(req, resp)
        }
        // 二进制直传
        else {
            doBinary(req, resp)
        }

    }

    private fun doBinary(req: HttpServletRequest, resp: HttpServletResponse) {
        val entity: ResponseEntity<FileBean> = ResponseEntity()
        val fileName = "myFile${System.currentTimeMillis()}"
        try {
            req.inputStream?.use { inputStream ->
                val path = Paths.get(fileDir.toString() + File.separator + fileName)
                Files.copy(inputStream, path, StandardCopyOption.REPLACE_EXISTING)

                val bean = FileBean()
                bean.fileName = fileName
                bean.url = realPath2Url(req, path.toFile().name)
                bean.length = path.toFile().length()
                entity.data = bean
                entity.msg = "上传成功"
                L.i("已保存： $bean")
            }
        } catch (e: Throwable) {
            e.printStackTrace()
            entity.msg = "接受失败： ${e.message}"
        }
        entity.sendBy(resp)
    }

    private fun doMultipart(req: HttpServletRequest, resp: HttpServletResponse) {
        // 响应体
        val entity: ResponseEntity<List<FileBean>> = ResponseEntity()
        val result = mutableListOf<FileBean>()
        entity.data = result
        try {
            // 检出含有文件的 part
            val parts = ArrayList(req.parts)
            // 如果包含文件
            if (parts.size > 0) {
                parts
                    .filter {
                        it.name != null
                    }
                    .filter {
                        it.submittedFileName != null
                    }
                    .forEach {
                        val fileName = it.submittedFileName
                        it.inputStream.use { inputStream ->
                            val path = Paths.get(fileDir.toString() + File.separator + fileName)
                            Files.copy(inputStream, path, StandardCopyOption.REPLACE_EXISTING)

                            val bean = FileBean()
                            bean.fileName = fileName
                            bean.url = realPath2Url(req, path.toFile().name)
                            bean.length = path.toFile().length()
                            result.add(bean)
                            L.i("已保存： $bean, ${path.toFile().canonicalPath}")
                        }
                        it.delete()
                    }
                entity.code = SUCCESSFUL_CODE
                entity.msg = "上传成功"
            } else {
                entity.code = FAILED_CODE
                entity.msg = "请上传文件"
            }
        } catch (e: Exception) {
            e.printStackTrace()
            entity.code = FAILED_CODE
            entity.msg = "上传错误：" + e.message
        }
        entity.sendBy(resp)
    }

}
